package com.platform.config;

import com.platform.comm.config.properties.JwtProperties;
import com.platform.config.properties.CustomSecurityProperties;
import com.platform.core.security.auth.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.List;

/**
 * @author sunzhubin.zh
 */
@Configuration
@EnableWebSecurity
@EnableConfigurationProperties({JwtProperties.class, CustomSecurityProperties.class})
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final UserDetailsService customUserDetailsService;
    private final CustomAuthenticationEntryPoint authenticationEntryPoint;
    private final CustomAccessDeniedHandler accessDeniedHandler;
    private final JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    private final VerifyAuthenticationFilter verifyAuthenticationFilter;
    private final CustomAuthenticationSuccessHandler successHandler;
    private final CustomAuthenticationFailureHandler failureHandler;
    private final CustomLogoutSuccessHandler logoutSuccessHandler;
    private final CustomSecurityProperties customSecurityProperties;

    @Autowired
    public WebSecurityConfig(UserDetailsService customUserDetailsService, CustomAuthenticationEntryPoint authenticationEntryPoint,
                             CustomAccessDeniedHandler accessDeniedHandler, JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter,
                             VerifyAuthenticationFilter verifyAuthenticationFilter, CustomAuthenticationSuccessHandler successHandler, CustomAuthenticationFailureHandler failureHandler, CustomLogoutSuccessHandler logoutSuccessHandler, CustomSecurityProperties customSecurityProperties) {
        this.customUserDetailsService = customUserDetailsService;
        this.authenticationEntryPoint = authenticationEntryPoint;
        this.accessDeniedHandler = accessDeniedHandler;
        this.jwtAuthenticationTokenFilter = jwtAuthenticationTokenFilter;
        this.verifyAuthenticationFilter = verifyAuthenticationFilter;

        this.successHandler = successHandler;
        this.failureHandler = failureHandler;
        this.logoutSuccessHandler = logoutSuccessHandler;
        this.customSecurityProperties = customSecurityProperties;
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public DaoAuthenticationProvider authProvider() {
        AuthenticationProviderImpl authProvider = new AuthenticationProviderImpl();
        authProvider.setHideUserNotFoundExceptions(false);
        authProvider.setUserDetailsService(customUserDetailsService);
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        //将自定的CustomUserDetailsService装配到AuthenticationManagerBuilder
//        auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
        auth.authenticationProvider(authProvider());
        auth.eraseCredentials(false);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        List<String> all = customSecurityProperties.getPermitAll();
        http.cors().and().csrf().disable();
        http
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests().filterSecurityInterceptorOncePerRequest(false)
                .antMatchers(all.toArray(new String[]{})).permitAll()
                .anyRequest().authenticated()//其他的路径都是登录后才可访问
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)
                .accessDeniedHandler(accessDeniedHandler)
                .and()
//                .formLogin()
//                .loginProcessingUrl("/auth/login")
//                .successHandler(successHandler)
//                .failureHandler(failureHandler)
//                .and()
                .logout()
                .logoutUrl("/auth/logout")
                .logoutSuccessHandler(logoutSuccessHandler)
                .permitAll().invalidateHttpSession(true);

        http.addFilterBefore(verifyAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        http.addFilterAt(myAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        http.headers().cacheControl();
    }

    @Bean
    CcbAuthenticationFilter myAuthenticationFilter() throws Exception {
        CcbAuthenticationFilter filter = new CcbAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManagerBean());
        filter.setAuthenticationSuccessHandler(successHandler);
        filter.setAuthenticationFailureHandler(failureHandler);
        return filter;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //解决静态资源被拦截的问题
        web.ignoring().antMatchers("/favicon.ico");
        super.configure(web);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new SM3PasswordEncoder();
    }
}
